import 'dart:async';
import 'dart:io';

import 'package:get/get.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:share_fit/app/controllers/base/base_controller.dart';
import 'package:share_fit/app/controllers/device/bind/device_bind_utils.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/tools/app_util.dart';
import 'package:share_fit/app/tools/log_utils.dart';
import 'package:share_fit/app/ute/uteped_config.dart';
import 'package:share_fit/app/ute/uteped_const.dart';
import 'package:share_fit/app/ute/uteped_device.dart';
import 'package:share_fit/generated/locales.g.dart';

import 'device_scan_state.dart';

class DeviceScanLogic extends BaseController implements DeviceChangeListener  {
  final DeviceScanState state = DeviceScanState();
  Timer? connectTimer;

  final MobileScannerController cameraController = MobileScannerController(
    detectionSpeed: DetectionSpeed.normal,
    facing: CameraFacing.back,
    torchEnabled: false,
    useNewCameraSelector: true,
    autoStart: false
  );

  StreamSubscription<Object?>? _subscription;

  @override
  void onInit() {
    super.onInit();
    UTEPedDevice.instance.addListener(this);
  }

  @override
  Future<void> onReady() async {
    var granted = await Permission.camera.isGranted;
    if (!granted) {
      granted = await Permission.camera.request().isGranted;
      if(!granted){
        showPermissionDialog(LocaleKeys.camera_permission_tips.ts);
      }
    }

    granted = await Permission.location.isGranted;
    if (!granted) {
      granted = await Permission.location.request().isGranted;
      if(!granted){
        showPermissionDialog(LocaleKeys.location_permission_tips.ts);
      }
    }

    if (Platform.isAndroid) {
      UTEPedConfig.instance.checkBluetoothPermissions();
    }

    _startCamera();
    super.onReady();
  }

  Future<void> connect(String address) async {
    logger.d("connect address: $address");
    state.address = address;
    UTEPedDevice.instance.connect(address, fromQrCode: true);
  }

  @override
  String getRemotePath() {
    return UTEPedConst.pathDevice;
  }

  @override
  void initState() {
    // TODO: implement initState
  }

  @override
  void onRemoteEvent(event, method) {
    if (method == UTEPedConst.methodConnect) {
      String address = event[UTEPedConst.keyAddress];
      int status = event[UTEPedConst.keyStatus];
      if (address == state.address) {
        if (status == UTEPedConst.stateConnected) {
          DeviceBindUtils.dismissDialog();
          Get.back();
          state.isConnecting = false;
        }
      }
    }
    update(["camera_scan"]);
  }

  String _getAddressFromBarcode(String barcode) {
    String macAddress = "";
    try {
      final pattern = RegExp(r'(([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2})');
      final match = pattern.firstMatch(barcode);

      if (match != null) {
         macAddress = match.group(0)!;
      }

    } catch (e) {
      logger.d(e);
    }

    // 如果mac地址不合法，置空
    if (!AppUtil.isValidMacAddress(macAddress)) {
      macAddress = "";
    }

    return macAddress;
  }

  void processBarcode(String barcode) {
    String address = _getAddressFromBarcode(barcode);
    logger.d("process mac address:$address");
    if (state.isConnecting || address.isEmpty) {
      logger.d("is connecting: $address");
      return;
    }
    state.isConnecting = true;

    try {
      DeviceBindUtils.showConnectingDialog(address);
      connect(address);
    } catch (e) {
      logger.d(e);
    }

    connectTimer = Timer(const Duration(seconds: 30), () {
      DeviceBindUtils.dismissDialog();
      Get.snackbar(LocaleKeys.info.ts, LocaleKeys.device_connect_timeout.ts);
      state.isConnecting = false;
    });

    update(["capture_image"]);
  }

  void _onBarcodeCapture(BarcodeCapture capture) {
    if (state.isConnecting) {
      logger.d("connecting");
      return;
    }
    final List<Barcode> barcodes = capture.barcodes;

    state.image = capture.image;
    for (final barcode in barcodes) {
      logger.d('Barcode found! ${barcode.rawValue}');
      String barcodeStr = "";
      String barcodeUrl = "";
      if (barcode.rawValue != null) {
        barcodeStr = barcode.rawValue.toString();
      }

      if (barcodeStr.isEmpty && barcode.displayValue != null) {
        barcodeStr = barcode.displayValue.toString();
      }

      if (barcodeStr.isEmpty || barcodeStr == barcodeUrl) {
        continue;
      }
      barcodeUrl = barcodeStr;

      processBarcode(barcodeStr);
    }
  }


  void _cancelConnectTimer() {
    connectTimer?.cancel();
    connectTimer = null;
  }

  bool _isCameraValid() {
    if (!cameraController.value.isInitialized ||
        cameraController.value.error?.errorCode == MobileScannerErrorCode.permissionDenied) {
      return false;
    }

    return true;
  }

  _startCamera() {
    _subscription = cameraController.barcodes.listen(_onBarcodeCapture);
    unawaited(cameraController.start());
  }

  _stopCamera() {
    if (_subscription != null) {
      unawaited(_subscription?.cancel());
      _subscription = null;
      unawaited(cameraController.stop());
    }
  }

  @override
  void onResumed() {
    super.onResumed();
    if (_isCameraValid()) {
      _startCamera();
    }
  }

  @override
  void onInactive() {
    if (_isCameraValid()) {
      _stopCamera();
    }
    super.onInactive();
  }

  @override
  void onClose() {
    _stopCamera();
    cameraController.dispose();
    UTEPedDevice.instance.removeListener(this);
    _cancelConnectTimer();
    DeviceBindUtils.dismissDialog();
    super.onClose();
  }

  @override
  void onDeviceChangeEvent(event) {
    String action = event[UTEPedConst.keyAction];
    if (action == UTEPedConst.actionConnectTimeout || action == UTEPedConst.actionConnectReject) {
      state.isConnecting = false;
      _cancelConnectTimer();
      DeviceBindUtils.dismissDialog();
    }
  }
}
